[小ネタ]Amazon Managed Workflowを既存VPC上に構築するためのポイント
どーもsutoです。
最近データ分析や機械学習のワークフローやバッチジョブのためにAirflowを勉強しています。また検証環境の構築に、AWSのマネージドサービスとしてリリースされたAmazon Managed Workflow for Apache Airflow(MWAA)を触っています。
MWAAの特徴や料金の概要については以下のブログがわかりやすいです。
しかし、構築した環境は時間で課金され、Webサーバ用インスタンスも一時停止できる機能はありません。(本来の運用では24時間稼働しておくものだから当然ですけどね) 料金体系も最小構成で「$0.49/hour」なので、環境を作っただけで放置しておくと決して安くはない費用が発生します。
毎日の業務で使用するわけではないので、検証で使用する時のみ環境を立ち上げ/削除を行っているのですが、手動でやるのはさすがに手間になるので、必要なリソースを自動構築するCloudFormationテンプレートを作成しました。
また、今回は既存VPCを利用して環境を構築してみようと思いますので、MWAA環境におけるVPCの要件や全体のAWS料金について抑えるべきポイントを含めてご紹介していきます。
MWAA環境のためのVPC要件と料金の話
公式ドキュメントによると、MWAA環境用のVPCには以下の要件があります。
- 同じリージョン内の2つの異なるアベイラビリティーゾーンにある2つのプライベートサブネット。
- また、次のいずれかが必要になります。
- 上記プライベートサブネットがインターネットに接続するためのNAT Gatewayを配置した2つのパブリックサブネット。
- 以下のVPCエンドポイント(AWS Private Link)が作成されていること
- Amazon CloudWatch
- CloudWatch Logs
- Amazon ECR
- Amazon S3
- Amazon SQS
- AWS Key Management Service
ここで、NAT GatewayもVPCエンドポイントも時間による課金が発生することにご注意ください。
つまり、MWAAの環境立ち上げた際のAWS料金は、
- MWAA環境料金 + MWAAワーカー料金 + メタデータストレージ料金 + (NAT Gateway料金 or PrivateLink(6つ)料金)
となり、最小構成の概算見積でも月額で$500〜はかかることになりそうです。
MWAAのメリットと課題
(2021/3/24時点のものとなりますが)
メリット
- マネージドサービスのため環境の維持が楽
- Dag、Pligin、RequirementsはS3バケットで管理
- airflow.cfgの設定がコンソールで直接管理できる
- IAMの機能でログインユーザ管理ができる
課題と制約
- スケジューラ、ワーカー、またはWebサーバーインスタンスにSSHで接続することはできない
- 各種ログはCloudwatch Logsに出力されます
- メタデータデータベースに直接アクセスしてDAG情報を照会することはできない。また、メタデータをエクスポートする機能はまだ実装されていない
- DAG関連の情報はUIメニューからAPIを利用してアクセス可能
- Airflowのバージョンが限定されている
- AWSは以前のAirflowバージョンでセキュリティ上の懸念を認識していたため、MWAAは最新の安定バージョンのみをサポートしているとのこと
- 2.0はまだ未対応
- Webサーバインスタンスの一時停止はできない
その他によくある質問にもいろいろ記載されていますのでご参照ください。
既存VPC上にMWAA環境を構築してみた
では実際に既存VPCを利用してMWAA環境をCloudFormationで構築してみましょう。
※MWAA環境用VPCを新規で構築する場合は公式のテンプレートでVPCを自動構築できますのでご参照ください。
- 以下のような、既存VPCがあることを前提とします
- 異なるAZにあるパブリックサブネット2つと、プライベートサブネット2つ
- インターネットゲートウェイがアタッチ済
- 各ルートテーブルに1つのサブネットが関連付け
- MWAA用のセキュリティグループは作成済(デフォルトのSGでも可)
ネットワーク要件で不足しているリソースを一緒に追加構築するので、今回はCloudFormationで以下のリソースを構築します。
- MWAA環境
- MWAAの実行IAMロール
- NAT Gateway2台
- EIP2つ(NAT Gatewayアタッチ用)
※今回のMWAAのUIへのアクセスは パブリック
とします。
※※プライベートの場合は環境構築後、プロキシサーバ構成またはELB構成などの追加のネットワーク設定が必要ですが本記事では紹介しません(参考)
テンプレート
AWSTemplateFormatVersion: 2010-09-09 Description: Resources creates an Amazon Managed Workflows for Apache Airflow (MWAA) environment Parameters: MWAAName: Description: The version of Apache Airflow. Type: String Default: MyAirflowEnvironment Version: Description: The version of Apache Airflow. Type: String Default: 1.10.12 BucketName: Description: The name of the S3 bucket that your environment accesses Type: String Default: bucket-name DagS3Path: Description: The relative path to the DAGs folder after your S3 bucket name. Type: String Default: /dags PluginS3Path: Description: The relative path to the plugins.zip file after your S3 bucket name. Type: String Default: /plugins.zip RequirementsS3Path: Description: The relative path to the requirements.txt file after your S3 bucket name. Type: String Default: /requirements.txt EnvClass: Description: The environment class name. Type: String Default: mw1.small AllowedValues: - mw1.small - mw1.medium - mw1.large Accessmode: Description: The environment class name. Type: String Default: PUBLIC_ONLY AllowedValues: - PUBLIC_ONLY - PRIVATE_ONLY MaxWorkerServer: Type: Number Default: 5 MaintenanceWindow: Description: 'format is DAY:HH:MM.' Type: String Default: 'SUN:03:00' PublicSubnetId1: Type: String PublicSubnetId2: Type: String PrivateSubnetId1: Type: String PrivateSubnetId2: Type: String MWAASGId: Type: String PrivateRouteTableId1: Type: String PrivateRouteTableId2: Type: String Resources: # MWAA Environment MWAA: Type: 'AWS::MWAA::Environment' Properties: AirflowVersion: !Ref Version SourceBucketArn: !Sub 'arn:aws:s3:::${BucketName}' DagS3Path: !Sub 's3://${BucketName}${DagS3Path}' PluginsS3Path: !Sub 's3://${BucketName}${PluginS3Path}' RequirementsS3Path: !Sub 's3://${BucketName}${RequirementsS3Path}' EnvironmentClass: !Ref EnvClass ExecutionRoleArn: !GetAtt MWAARole.Arn LoggingConfiguration: TaskLogs: Enabled: true LogLevel: INFO SchedulerLogs: Enabled: false LogLevel: WARNING WebserverLogs: Enabled: false LogLevel: WARNING WorkerLogs: Enabled: false LogLevel: WARNING DagProcessingLogs: Enabled: false LogLevel: WARNING MaxWorkers: !Ref MaxWorkerServer Name: !Ref MWAAName NetworkConfiguration: SecurityGroupIds: - !Ref MWAASGId SubnetIds: - !Ref PrivateSubnetId1 - !Ref PrivateSubnetId2 WebserverAccessMode: !Ref Accessmode WeeklyMaintenanceWindowStart: !Ref MaintenanceWindow # IAM Role MWAARole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${MWAAName}-MWAA-role' Path: /service-role/ AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - airflow-env.amazonaws.com - airflow.amazonaws.com Action: - 'sts:AssumeRole' Policies: - PolicyName: !Sub 'MWAA-${MWAAName}-Execution-Policy' PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: 'airflow:PublishMetrics' Resource: - !Sub "arn:aws:airflow:${AWS::Region}:${AWS::AccountId}:environment/${MWAAName}" - Effect: Deny Action: 's3:ListAllMyBuckets' Resource: - !Sub 'arn:aws:s3:::${BucketName}' - !Sub 'arn:aws:s3:::${BucketName}/*' - Effect: Allow Action: - 's3:GetObject*' - 's3:GetBucket*' - 's3:List*' Resource: - !Sub 'arn:aws:s3:::${BucketName}' - !Sub 'arn:aws:s3:::${BucketName}/*' - Effect: Allow Action: - 'logs:CreateLogStream' - 'logs:CreateLogGroup' - 'logs:PutLogEvents' - 'logs:GetLogEvents' - 'logs:PutLogEvents' - 'logs:GetLogRecord' - 'logs:GetLogGroupFields' - 'logs:GetQueryResults' Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:airflow-${MWAAName}-*' - Effect: Allow Action: 'logs:DescribeLogGroups' Resource: '*' - Effect: Allow Action: 'cloudwatch:PutMetricData' Resource: '*' - Effect: Allow Action: - 'sqs:ChangeMessageVisibility' - 'sqs:DeleteMessage' - 'sqs:GetQueueAttributes' - 'sqs:GetQueueUrl' - 'sqs:ReceiveMessage' - 'sqs:SendMessage' Resource: - !Sub 'arn:aws:logs:${AWS::Region}:*:airflow-celery-*' - Effect: Allow Action: - 'kms:Decrypt' - 'kms:DescribeKey' - 'kms:GenerateDataKey*' - 'kms:Encrypt' NotResource: - !Sub 'arn:aws:kms:*:${AWS::AccountId}:key/*' Condition: StringLike: 'kms:ViaService': - sqs.ap-northeast-1.amazonaws.com # NAT Gateway, EIP DefaultPrivateRoute1: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref PrivateRouteTableId1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: RouteTableId: !Ref PrivateRouteTableId1 SubnetId: !Ref PrivateSubnetId1 DefaultPrivateRoute2: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref PrivateRouteTableId2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 PrivateSubnet2RouteTableAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: RouteTableId: !Ref PrivateRouteTableId2 SubnetId: !Ref PrivateSubnetId2 NatGateway1EIP: Type: 'AWS::EC2::EIP' Properties: Domain: vpc NatGateway2EIP: Type: 'AWS::EC2::EIP' Properties: Domain: vpc NatGateway1: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnetId1 NatGateway2: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnetId2
これで作成したまま放置すると課金が発生するリソースを一括で作成・削除ができますね。入力したパラメータはクイックリンクを生成しておけば楽だし、CDKで管理するようにしてもOKですね。
まとめ
今回は既存VPCにMWAA環境を構築するテンプレートと、MWAAの特徴、課題点、VPC要件についてのご紹介でした。
Airflow2.0の対応やメタデータのエクスポート機能辺りは今後のアップデートに期待したいところです。スモール構成でいくつか簡単なジョブを動かしてみましたが、パフォーマンスはちょっとモッサリな印象でした。(あくまで主観です)
ですが、GCPのCloud Composerと違い、ワーカーがAutoscalingするという利点も加えて、Airflowの環境維持に関する負担は非常に軽減されると思います。